package com.hodgepodge.sso.filter;

import com.alibaba.fastjson.JSON;
import com.hodgepodge.api.dto.LoginUserDTO;
import com.hodgepodge.commons.base.entity.Result;
import com.hodgepodge.commons.enums.ResultCodeEnum;
import com.hodgepodge.sso.entity.JwtAuthUser;
import com.hodgepodge.utils.JwtTokenUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * title JwtLoginAuthFilter
 * projectName colorful-blog
 * desc 进行用户账号的验证==>认证功能
 *
 * @author jiangjian
 * @date 2021/7/6 14:48
 */
public class JwtLoginAuthFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    private ThreadLocal<Boolean> rememberMe = new ThreadLocal<>();

    public JwtLoginAuthFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        // 设置该过滤器地址
        super.setFilterProcessesUrl("/login");
    }

    /**
     * 登录验证
     *
     * @param request  请求信息
     * @param response 响应信息
     * @return 认证信息
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        LoginUserDTO loginUser = new LoginUserDTO();
        loginUser.setUsername(request.getParameter("username"));
        loginUser.setPassword(request.getParameter("password"));
        loginUser.setRememberMe(Boolean.parseBoolean(request.getParameter("rememberMe")));
        rememberMe.remove();
        rememberMe.set(loginUser.getRememberMe());
        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList<>())
        );
    }

    /**
     * 登录验证成功后调用，验证成功后将生成Token，并重定向到用户主页home
     * 与AuthenticationSuccessHandler作用相同
     *
     * @param request    请求信息
     * @param response   响应信息
     * @param chain      chain
     * @param authResult 认证信息
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException {

        // 查看源代码会发现调用getPrincipal()方法会返回一个实现了`UserDetails`接口的对象，这里是JwtAuthUser
        JwtAuthUser jwtUser = (JwtAuthUser) authResult.getPrincipal();
        boolean isRemember = rememberMe.get();
        List<String> roles = new ArrayList<>();
        Collection<? extends GrantedAuthority> authorities = jwtUser.getAuthorities();
        for (GrantedAuthority authority : authorities) {
            roles.add(authority.getAuthority());
        }
        String token = JwtTokenUtils.createToken(jwtUser.getUsername(), roles, isRemember);
        // 重定向无法设置header,这里设置header只能设置到/login界面的header
        // response.setHeader("token", JwtTokenUtils.TOKEN_PREFIX + token);

        // 登录成功重定向到home界面 这里先采用参数传递
        response.sendRedirect("/home?token=" + token);
    }

    /**
     * 登录验证失败后调用，这里直接Json返回，实际上可以重定向到错误界面等
     * 与AuthenticationFailureHandler作用相同
     *
     * @param request  请求信息
     * @param response 响应信息
     * @param failed   认证失败信息
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(JSON.toJSONString(Result.result(ResultCodeEnum.INVALID_USERNAME_PASSWORD)));
    }


}
